﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;

namespace mesoBoard.Data.Repositories
{
    public class UserRepository : IUserRepository
    {
        private mbEntities db;

        public UserRepository(mbEntities mbDataContext)
        {
            this.db = mbDataContext;
        }

        public void SyncUser(int UserID)
        {
            User TheUser = GetUser(UserID);
            IEnumerable<Post> posts = db.Posts.Where(x => x.UserID == UserID).OrderByDescending(x => x.Date);
            Post firstPost = posts.FirstOrDefault();

            if (firstPost != null) TheUser.LastPostDate = firstPost.Date;

            TheUser.TotalPosts = posts.Count();
            TheUser.UsernameLower = TheUser.Username.ToLower();
            int themeID = TheUser.UserProfile.ThemeID;
            Theme TheTheme = db.Themes.FirstOrDefault(x => x.ThemeID == themeID);

            if (TheTheme == null)
                TheUser.UserProfile.ThemeID = db.Themes.FirstOrDefault().ThemeID;

            db.SaveChanges();
        }

        public void SyncAllUsers()
        {
            foreach (User u in db.Users.AsEnumerable())
            {
                SyncUser(u.UserID);
            }
        }

        public void CreateUser(User TheUser)
        {
            db.Users.AddObject(TheUser);
            db.SaveChanges();
            InRole NewUserRole = new InRole
            {
                UserID = TheUser.UserID,
                RoleID = 3
            };
            db.InRoles.AddObject(NewUserRole);
            db.SaveChanges();
            db.UserProfiles.AddObject(new UserProfile
            {
                AlwaysShowSignature = true,
                Avatar = "",
                Location = "",
                Signature ="",
                ThemeID = int.Parse(db.Configs.FirstOrDefault(x=>x.Name=="BoardTheme").Value),
                UserID = TheUser.UserID,
                AvatarType = "None"
            });
            db.SaveChanges();

        }

        public void DeleteUser(int UserID)
        {
            db.Users.DeleteObject(GetUser(UserID));
            db.SaveChanges();
        }

        public User GetUserByEmail(string Email)
        {
            return db.Users.FirstOrDefault(x => x.Email.ToLower() == Email.ToLower());
        }

        public void UpdateLastLogout(int UserID)
        {
            db.Users.First(x => x.UserID == UserID).LastLogoutDate = DateTime.UtcNow;
            db.SaveChanges();
        }

        public void UpdateLastLogin(int UserID, string LastLoginIP)
        {
            User TheUser = db.Users.FirstOrDefault(x => x.UserID == UserID);
            TheUser.LastLogoutDate = TheUser.LastLoginDate;
            TheUser.LastLoginDate = DateTime.UtcNow;
            TheUser.LastLoginIP = LastLoginIP;
            db.SaveChanges();
        }

        public User GetUser(int UserID)
        {
            return db.Users.FirstOrDefault(x => x.UserID == UserID);
        }

        public User GetUser(string userName)
        {
            return db.Users.FirstOrDefault(x => x.UsernameLower == userName.Trim().ToLower());
        }

        public User OBSGetUser(string UserNameOrIDOrEmail)
        {
            UserNameOrIDOrEmail = UserNameOrIDOrEmail.Trim().ToLower();
            if (UserExists(UserNameOrIDOrEmail))
            {
                int UserID;
                bool IsInt = int.TryParse(UserNameOrIDOrEmail, out UserID);
                if (IsInt)
                {
                    return db.Users.FirstOrDefault(x => x.UserID == UserID);
                }
                else
                {
                    return db.Users.FirstOrDefault(x => x.UsernameLower == UserNameOrIDOrEmail);
                }
            }
            else if(EmailInUse(UserNameOrIDOrEmail))
            {
                return GetUserByEmail(UserNameOrIDOrEmail);
            }
            else
            {
                return null;
            }
        }

        public bool EmailInUse(string Email)
        {
            return db.Users.FirstOrDefault(x => x.Email.ToLower() == Email.Trim().ToLower()) != null;
        }

        public bool UserExists(string UserNameOrID)
        {
            int UserID;
            User TheUser;
            bool IsInt = int.TryParse(UserNameOrID, out UserID);
            if (IsInt)
                TheUser = db.Users.FirstOrDefault(x => x.UserID == UserID);
            else
                TheUser = db.Users.FirstOrDefault(x => x.UsernameLower == UserNameOrID.ToLower());

            return TheUser != null;
        }

        public void SubmitChanges()
        {
            db.SaveChanges();
        }

        public bool ValidateUser(string Username, string Password)
        {
            User TheUser = GetUser(Username);

            return (TheUser != null && TheUser.Password == Password && string.IsNullOrEmpty(TheUser.ActivationCode));
        }

        public string[] GetUserRoles(string UserNameOrID)
        {
            User TheUser = GetUser(int.Parse(UserNameOrID));
            var UserRoles = (from r in db.InRoles
                             where r.UserID == TheUser.UserID
                             select r).Select(x => x.Role.Name).ToArray();
            return UserRoles;
        }

        public bool ActivateUser(string Username, string ActivationCode)
        {
            if (UserExists(Username))
            {
                User TheUser = GetUser(Username);
                if (TheUser.ActivationCode == ActivationCode)
                {
                    TheUser.ActivationCode = string.Empty;
                    db.SaveChanges();
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        public void UpdateProfile(UserProfile TheProfile)
        {
            if (TheProfile.EntityKey == null)
                TheProfile.EntityKey = ((UserProfile)db.GetObjectByKey(new System.Data.EntityKey("mbEntities.UserProfiles", "UserID", TheProfile.UserID))).EntityKey;

            db.UserProfiles.ApplyCurrentValues(TheProfile);
            db.SaveChanges();
        }

        public void UpdateUser(User TheUser)
        {
            if (TheUser.EntityKey == null)
                TheUser.EntityKey = ((User)db.GetObjectByKey(new System.Data.EntityKey("mbEntities.Users", "UserID", TheUser.UserID))).EntityKey;

            db.Users.ApplyCurrentValues(TheUser);
            db.SaveChanges();
        }

        public UserProfile GetUserProfile(int UserID)
        {
            return db.UserProfiles.First(x => x.UserID == UserID);
        }

        public int TotalUsers()
        {
            return db.Users.Where(x=>x.ActivationCode == string.Empty).Count();
        }

        public User NewestUser()
        {
            return db.Users.OrderByDescending(x => x.RegisterDate).First();
        }

        public IEnumerable<User> BirthdayUsers()
        {
            return null; //db.Users.Where(x => x.Birthdate.Month == DateTime.UtcNow.Month && x.Birthdate.Day == DateTime.UtcNow.Day);
        }

        public IEnumerable<User> UsersInRole(int RoleID)
        {
            return db.Users.SelectMany(x => x.InRoles.Where(y => y.RoleID == RoleID)).Select(x=>x.User);
        }

        public IEnumerable<User> GetAllUsers()
        {
            return db.Users.AsEnumerable();
        }

        public void CreatePasswordResetRequest(PasswordResetRequest ThePasswordResetRequest)
        {
            db.PasswordResetRequests.AddObject(ThePasswordResetRequest);
            db.SaveChanges();
        }

        public void DeletePasswordResetRequest(int UserID)
        {
            db.PasswordResetRequests.DeleteObject(db.PasswordResetRequests.FirstOrDefault(x => x.UserID == UserID));
            db.SaveChanges();
        }

        public PasswordResetRequest GetPasswordResetRequest(int UserID)
        {
            return db.PasswordResetRequests.FirstOrDefault(x => x.UserID == UserID);
        }

    }
}
